import 'dart:convert';

import 'package:efood_multivendor/controller/category_controller.dart';
import 'package:efood_multivendor/controller/coupon_controller.dart';
import 'package:efood_multivendor/controller/filter_controller.dart';
import 'package:efood_multivendor/controller/order_controller.dart';
import 'package:efood_multivendor/data/api/api_checker.dart';
import 'package:efood_multivendor/data/model/body/checkout_body_model.dart';
import 'package:efood_multivendor/data/model/body/place_order_body.dart';
import 'package:efood_multivendor/data/model/response/category_model.dart';
import 'package:efood_multivendor/data/model/response/checkout_response_model.dart';
import 'package:efood_multivendor/data/model/response/product_model.dart';
import 'package:efood_multivendor/data/model/response/restaurant_model.dart';
import 'package:efood_multivendor/data/model/response/review_model.dart';
import 'package:efood_multivendor/data/repository/restaurant_repo.dart';
import 'package:efood_multivendor/helper/price_converter.dart';
import 'package:efood_multivendor/view/base/custom_snackbar.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';

class RestaurantController extends GetxController implements GetxService {
  final RestaurantRepo restaurantRepo;
  RestaurantController({required this.restaurantRepo});

  List<Restaurant>? _restaurantList;
  List<Restaurant>? _popularRestaurantList;
  List<Restaurant>? _latestRestaurantList;
  Restaurant? _restaurant;
  List<Product>? _restaurantProducts;
  int _categoryIndex = 0;
  List<CategoryModel>? _categoryList;
  bool _isLoading = false;
  int _pageSize = 10;
  List<String> _offsetList = [];
  int _offset = 1;
  String _restaurantType = 'all';
  List<ReviewModel>? _restaurantReviewList;
  bool _foodPaginate = false;
  int _foodPageSize = 0;
  List<int> _foodOffsetList = [];
  int _foodOffset = 1;
  String _type = 'all';
  String _searchText = '';
  List<Product>? _searchProductList;
  bool _isSearching = false;
  String _prodResultText = '';
  bool _searchProductPaginate = false;
  int _searchProductPageSize = 0;
  int _searchProductOffset = 1;
  bool _isSearchQueryEmpty = false;
  CheckoutApiResponse? _checkoutData;
  bool _isCouponLoading = false;

  List<Restaurant>? get restaurantList => _restaurantList;
  List<Restaurant>? get popularRestaurantList => _popularRestaurantList;
  List<Restaurant>? get latestRestaurantList => _latestRestaurantList;
  Restaurant? get restaurant => _restaurant;
  List<Product>? get restaurantProducts => _restaurantProducts;
  int get categoryIndex => _categoryIndex;
  List<CategoryModel>? get categoryList => _categoryList;
  bool get isLoading => _isLoading;
  int get popularPageSize => _pageSize;
  int get offset => _offset;
  String get restaurantType => _restaurantType;
  List<ReviewModel>? get restaurantReviewList => _restaurantReviewList;
  bool get foodPaginate => _foodPaginate;
  int get foodPageSize => _foodPageSize;
  int get foodOffset => _foodOffset;
  String get type => _type;
  String get searchText => _searchText;
  List<Product>? get searchProductList => _searchProductList;
  bool get isSearching => _isSearching;
  bool get searchProductPaginate => _searchProductPaginate;
  int get searchProductPageSize => _searchProductPageSize;
  int get searchProductOffset => _searchProductOffset;
  bool get isSearchQueryEmpty => _isSearchQueryEmpty;
  CheckoutApiResponse? get checkoutData => _checkoutData;
  bool get isCouponLoading => _isCouponLoading;

  void setOffset(int offset) {
    _offset = offset;
  }

  Future<void> getRestaurantList(String offset, bool reload) async {
    if (offset == '1' || reload) {
      _offsetList = [];
      _offset = 1;
      if (reload) {
        _restaurantList = null;
      }
      update();
    }
    if (!_offsetList.contains(offset)) {
      _offsetList.add(offset);
      String? sort;
      String? price_range;
      FilterController filterController = Get.find<FilterController>();
      if (filterController.isSet) {
        price_range =
            "${filterController.priceLower},${filterController.priceHigher}";
        switch (filterController.sortMode) {
          case SortMode.Distance:
            sort = 'distance';
            break;
          case SortMode.Rating:
            sort = 'rating';
            break;
          case SortMode.CostAsc:
            sort = 'price_asc';
            break;
          case SortMode.CostDesc:
            sort = 'price_desc';
            break;
        }
      }

      Response response = await restaurantRepo.getRestaurantList(
          offset, _restaurantType, sort, price_range ?? '');
      if (response.statusCode == 200) {
        if (offset == '1') {
          _restaurantList = [];
        }
        _restaurantList
            ?.addAll(RestaurantModel.fromJson(response.body).restaurants ?? []);
        _pageSize = RestaurantModel.fromJson(response.body).totalSize ?? 0;
        _isLoading = false;
        update();
      } else {
        ApiChecker.checkApi(response);
      }
    } else {
      if (isLoading) {
        _isLoading = false;
        update();
      }
    }
  }

  void setRestaurantType(String type) {
    _restaurantType = type;
    getRestaurantList('1', true);
  }

  Future<void> getPopularRestaurantList(
      bool reload, String type, bool notify) async {
    _type = type;
    if (reload) {
      _popularRestaurantList = null;
    }
    if (notify) {
      update();
    }
    if (_popularRestaurantList == null || reload) {
      Response response = await restaurantRepo.getPopularRestaurantList(type);
      if (response.statusCode == 200) {
        _popularRestaurantList = [];
        response.body.forEach((restaurant) =>
            _popularRestaurantList!.add(Restaurant.fromJson(restaurant)));
      } else {
        ApiChecker.checkApi(response);
      }
      update();
    }
  }

  Future<void> getLatestRestaurantList(
      bool reload, String type, bool notify) async {
    _type = type;
    if (reload) {
      _latestRestaurantList = null;
    }
    if (notify) {
      update();
    }
    if (_latestRestaurantList == null || reload) {
      Response response = await restaurantRepo.getLatestRestaurantList(type);
      if (response.statusCode == 200) {
        _latestRestaurantList = [];
        response.body.forEach((restaurant) =>
            _latestRestaurantList!.add(Restaurant.fromJson(restaurant)));
      } else {
        ApiChecker.checkApi(response);
      }
      update();
    }
  }

  void setCategoryList() {
    if (Get.find<CategoryController>().categoryList != null &&
        _restaurant != null) {
      _categoryList = [];
      _categoryList!.add(CategoryModel(id: 0, name: 'all'.tr));
      Get.find<CategoryController>().categoryList?.forEach((category) {
        if (_restaurant?.categoryIds?.contains(category.id) == true) {
          _categoryList!.add(category);
        }
      });
    }
  }

  void initCheckoutData(int restaurantID, CheckoutBody checkoutBody) {
    if (_restaurant == null ||
        _restaurant!.id != restaurantID ||
        Get.find<OrderController>().distance == null) {
      Get.find<CouponController>().removeCouponData(false);
      Get.find<OrderController>().clearPrevData();
      Get.find<RestaurantController>()
          .getRestaurantDetails(Restaurant(id: restaurantID), 'checkout');
      Get.find<RestaurantController>().checkout(checkoutBody);
    } else {
      Get.find<OrderController>().initializeTimeSlot(_restaurant!);
    }
  }

  Future<Restaurant?> getRestaurantDetails(
      Restaurant restaurant, String referer) async {
    _categoryIndex = 0;
    if (restaurant.name != null) {
      _restaurant = restaurant;
    } else {
      _isLoading = true;
      _restaurant = null;
      Response response = await restaurantRepo.getRestaurantDetails(
          restaurant.id.toString(), referer);
      if (response.statusCode == 200) {
        _restaurant = Restaurant.fromJson(response.body);
        Get.find<OrderController>().initializeTimeSlot(_restaurant!);
      } else {
        ApiChecker.checkApi(response);
      }
      Get.find<OrderController>().setOrderType(
        _restaurant != null
            ? _restaurant!.delivery == true
                ? 'delivery'
                : 'take_away'
            : 'delivery',
        notify: false,
      );

      _isLoading = false;
      update();
    }
    return _restaurant;
  }

  Future<CheckoutApiResponse?> checkout(CheckoutBody checkoutBody,
      {bool isAlphaLoading = false}) async {
    if (isAlphaLoading == true) {
      //
    } else if (checkoutBody.couponCode != null &&
        checkoutBody.couponCode?.isNotEmpty == true) {
      _isCouponLoading = true;
      update();
    } else {
      _checkoutData = null;
      _isLoading = true;
    }

    Response response = await restaurantRepo.checkout(checkoutBody);

    if (response.statusCode == 200) {
      try {
        _checkoutData = CheckoutApiResponse.fromJson(response.body);

        if (_checkoutData?.message?.isNotEmpty == true) {
          showCustomSnackBar(_checkoutData!.message);
        }

        if (checkoutBody.couponCode != null &&
            checkoutBody.couponCode?.isNotEmpty == true) {
          if (_checkoutData!.data!.couponDiscountAmount! > 0 &&
              _checkoutData!.data!.coupon?.freeDelivery == true) {
            showCustomSnackBar(
              '${'you_got_a_free_delivery'.tr}}',
              isError: false,
            );
          } else if (_checkoutData!.data!.couponDiscountAmount! > 0) {
            showCustomSnackBar(
              '${'you_got_discount_of'.tr} ${PriceConverter.convertPrice(_checkoutData!.data!.couponDiscountAmount!.toDouble())}',
              isError: false,
            );
          }
        }
        // } else {
        // if (_checkoutData.message.isNotEmpty) {
        //   showCustomSnackBar(_checkoutData.message);
        //   // if (checkoutBody.couponCode != null &&
        //   //     checkoutBody.couponCode.isNotEmpty) {
        //   // } else {
        //   //   _checkoutData = null;
        //   // }
        // }

        // }
      } catch (e) {
        _isLoading = false;
        _isCouponLoading = false;
        showCustomSnackBar('an error occured');
        print(e.toString());
        rethrow;
      }

      _isLoading = false;
      _isCouponLoading = false;
    } else {
      _isLoading = false;
      _isCouponLoading = false;
      if (checkoutBody.couponCode != null &&
          checkoutBody.couponCode?.isNotEmpty == true) {
        showCustomSnackBar(_checkoutData?.message);
      } else {
        ApiChecker.checkApi(response);
      }
    }
    update();
    return _checkoutData;
  }

  Future<void> getRestaurantProductList(
      int restaurantID, int offset, String type, bool notify) async {
    _foodOffset = offset;
    if (offset == 1 || _restaurantProducts == null) {
      _type = type;
      _foodOffsetList = [];
      _restaurantProducts = null;
      _foodOffset = 1;
      if (notify) {
        update();
      }
    }
    if (!_foodOffsetList.contains(offset)) {
      _foodOffsetList.add(offset);
      Response response = await restaurantRepo.getRestaurantProductList(
        restaurantID,
        offset,
        (_restaurant != null &&
                _restaurant!.categoryIds!.length > 0 &&
                _categoryIndex != 0)
            ? _categoryList![_categoryIndex].id!
            : 0,
        type,
      );
      if (response.statusCode == 200) {
        if (offset == 1) {
          _restaurantProducts = [];
        }
        _restaurantProducts
            ?.addAll(ProductModel.fromJson(response.body).products ?? []);
        _foodPageSize = ProductModel.fromJson(response.body).totalSize ?? 0;
        _foodPaginate = false;
        update();
      } else {
        ApiChecker.checkApi(response);
      }
    } else {
      if (_foodPaginate) {
        _foodPaginate = false;
        update();
      }
    }
  }

  Future<List<String>> searchKeyword(BuildContext context, String keyword,
      String referer, String restaurantID) async {
    List<String> _suggestedKeywordList = [];

    if (keyword.isNotEmpty) {
      //print("Searching for: $keyword");

      try {
        Response response = await restaurantRepo.getSuggestedKeywords(
            keyword, referer, restaurantID);

        if (response.statusCode == 200) {
          String decodedBody = response.bodyString!;
          List<dynamic> decodedData = jsonDecode(decodedBody);
          _suggestedKeywordList = decodedData.whereType<String>().toList();
        } else {
          print("Error: ${response.statusCode}");
        }
      } catch (e) {
        print("Exception: $e");
      }
    } else {
      print("Keyword is null or empty");
    }

    return _suggestedKeywordList;
  }

  void showFoodBottomLoader() {
    _foodPaginate = true;
    update();
  }

  void setFoodOffset(int offset) {
    _foodOffset = offset;
  }

  void showBottomLoader() {
    _isLoading = true;
    update();
  }

  void setCategoryIndex(int index) {
    _categoryIndex = index;
    _restaurantProducts = null;
    if (_restaurant != null) {
      getRestaurantProductList(
          _restaurant!.id!, 1, Get.find<RestaurantController>().type, false);
    }
    update();
  }

  Future<void> getRestaurantReviewList(String restaurantID) async {
    _restaurantReviewList = null;
    Response response =
        await restaurantRepo.getRestaurantReviewList(restaurantID);
    if (response.statusCode == 200) {
      _restaurantReviewList = [];
      response.body.forEach(
          (review) => _restaurantReviewList?.add(ReviewModel.fromJson(review)));
    } else {
      ApiChecker.checkApi(response);
    }
    update();
  }

  bool isRestaurantClosed(bool today, bool active, String offDay) {
    offDay = offDay.trim();
    DateTime _date = DateTime.now();
    if (!today) {
      _date = _date.add(Duration(days: 1));
    }
    for (int index = 0; index < offDay.length; index++) {
      if (_date.weekday == int.parse(offDay[index])) {
        return true;
      }
    }
    return !active;
  }

  void searchData(String query, String restaurantID) async {
    if (query.trim().isNotEmpty && query != _prodResultText) {
      _searchText = query;
      _searchProductList = null;
      _isSearching = true;
      update();
      if (query.trim().isEmpty) {
        _searchProductList = [];
      } else {
        Response response = await restaurantRepo.getSearchData(
            query, restaurantID, _searchProductOffset);
        if (response.statusCode == 200) {
          _prodResultText = query;
          _searchProductList = [];
          _searchProductList
              ?.addAll(ProductModel.fromJson(response.body).products ?? []);
          _searchProductPageSize =
              RestaurantModel.fromJson(response.body).totalSize ?? 0;
        } else {
          ApiChecker.checkApi(response);
        }
      }
      update();
    } else {
      _searchProductList = _restaurantProducts;
      _isSearchQueryEmpty = true;
      update();
    }
  }

  void toggleSearch() {
    Get.back();
    _isSearching = !_isSearching;
    _searchProductList = [];
    _prodResultText = '';
    update();
  }

  void setSearchProductOffset(int offset) {
    _searchProductOffset = offset;
  }
}
